#include "registerdialog.h"
#include "ui_registerdialog.h"

#include <QException>

RegisterDialog::RegisterDialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::RegisterDialog), _countdown(5)
{
    ui->setupUi(this);

    // 设置密码和确认密码QLineEdit输入模式为密码模式
    ui->confirm_edit->setEchoMode(QLineEdit::Password);
    ui->pass_edit->setEchoMode(QLineEdit::Password);

    // 给err_tip添加样式
    ui->err_tip->setProperty("state", "normal");
    repolish(ui->err_tip);

    // HttpMgr的注册信号连接到RegisterDialog的注册槽函数
    connect(HttpMgr::GetInstance().get(), &HttpMgr::sig_reg_mod_finish, this, &RegisterDialog::slot_reg_mod_finish);
    initHttpHandlers(); // 消息处理的声明和定义

    // 调整输入框错误提示
    ui->err_tip->clear();

    connect(ui->user_edit, &QLineEdit::editingFinished, this, [this](){
        checkUserValid();
    });
    connect(ui->email_edit, &QLineEdit::editingFinished, this, [this](){
        checkEmailValid();
    });
    connect(ui->pass_edit, &QLineEdit::editingFinished, this, [this](){
        checkPassValid();
    });
    connect(ui->confirm_edit, &QLineEdit::editingFinished, this, [this](){
        checkConfirmValid();
    });
    connect(ui->varify_edit, &QLineEdit::editingFinished, this, [this](){
        checkVarifyValid();
    });

    // 密码和确认密码是否显示的设置
    ui->pass_visible->setCursor(Qt::PointingHandCursor);
    ui->confirm_visible->setCursor(Qt::PointingHandCursor);

    // 注意设置 pass_visible 和 confirm_visible 提升为 ClickedLabel
    ui->pass_visible->SetState("unvisible", "unvisible_hover", "", "visible", "visible_hover", "");
    ui->confirm_visible->SetState("unvisible", "unvisible_hover", "", "visible", "visible_hover", "");
    // 连接点击事件
    connect(ui->pass_visible, &ClickedLabel::clicked, this, [this](){
        auto state = ui->pass_visible->GetCurState();
        if(state == ClickLbState::Normal)
            ui->pass_edit->setEchoMode(QLineEdit::Password);
        else
            ui->pass_edit->setEchoMode(QLineEdit::Normal);
        qDebug() << "Label was clicked!";
    });
    connect(ui->confirm_visible, &ClickedLabel::clicked, this, [this](){
        auto state = ui->confirm_visible->GetCurState();
        if(state == ClickLbState::Normal)
            ui->confirm_edit->setEchoMode(QLineEdit::Password);
        else
            ui->confirm_edit->setEchoMode(QLineEdit::Normal);
        qDebug() << "Labled was clikced";
    });

    // 注册成功后的界面切换
    // 创建定时器
    _countdown_timer = new QTimer(this);
    // 连接信号和槽
    connect(_countdown_timer, &QTimer::timeout, [this](){
        if(_countdown == 0){
            _countdown_timer->stop();
            emit sigSwitchLogin();
            return;
        }
        _countdown--;
        auto str = QString("注册成功, %1 s后返回登陆").arg(_countdown);
        ui->tip_lb->setText(str);
    });
}

RegisterDialog::~RegisterDialog()
{
    delete ui;
}


// 消息处理的声明和定义
void RegisterDialog::initHttpHandlers(){
    // 注册获取验证码回包逻辑
    _handlers.insert(ReqId::ID_GET_VARIFY_CODE, [this](QJsonObject jsonObj){
        int error = jsonObj["error"].toInt();
        if(error != ErrorCodes::SUCCESS){
            showTip(tr("参数错误"), false);
            return;
        }

        auto email = jsonObj["email"].toString();
        showTip(tr("验证码已发送到邮箱，注意查收"), true);
        qDebug() << "email is" << email;
    });

    // 注册用户回包逻辑
    _handlers.insert(ReqId::ID_REG_USER, [this](QJsonObject jsonObj){
        int error = jsonObj["error"].toInt();
        if(error != ErrorCodes::SUCCESS){
            if(error == ErrorCodes::VarifyExpired) showTip(tr("验证码已过期"), false);
            if(error == ErrorCodes::UserExist) showTip(tr("name或者email已经存在"), false);
            else showTip(tr("参数错误"), false);
            return;
        }
        showTip(tr("用户注册成功"), true);
        qDebug() << "user uuid is " << jsonObj["uuid"].toString();
        auto email = jsonObj["email"].toString();
        qDebug() << "email is " << email;

        // 注册成功后的页面切换
        ChangeTipPage();
    });
}

// 获取验证码按钮的槽函数
void RegisterDialog::on_get_code_clicked()
{
    // 验证邮箱的地址正则表达式
    auto email = ui->email_edit->text();
    // 邮箱地址的正则表达式
    // 18175549596@163.com
    QRegularExpression regex(R"((\w+)(\.|_)?(\w*)@(\w+)(\.(\w+))+)");
    bool match = regex.match(email).hasMatch(); // 执行正则表达式匹配
    if(match == true){
        // 发送http请求获取验证码
        showTip(tr("邮箱正确"), true);
        QJsonObject json_obj;
        json_obj["email"] = email;
        // HttpMgr::GetInstance()->PostHttpReq(QUrl("http://localhost:8081/get_varifycode"), json_obj, ReqId::ID_GET_VARIFY_CODE, Modules::REGISTERMOD);
        HttpMgr::GetInstance()->PostHttpReq(QUrl(gate_url_prefix + "/get_varifycode"), json_obj, ReqId::ID_GET_VARIFY_CODE, Modules::REGISTERMOD);
    }else{
        // 提示邮箱不正确
        showTip(tr("邮箱不正确"), false);
    }
}

// 注册信号触发的注册槽函数
void RegisterDialog::slot_reg_mod_finish(ReqId id, QString res, ErrorCodes err){
    // 网络请求错误
    if(err != ErrorCodes::SUCCESS){
        showTip(tr("网络请求错误"), false);
        return;
    }

    // 解析JSON字符串，res需转化为QByteArray
    QJsonDocument jsonDoc = QJsonDocument::fromJson(res.toUtf8());
    // json解析错误
    if(jsonDoc.isNull()){
        showTip(tr("返回json为空"), false);
        return;
    }
    // json解析错误
    if(jsonDoc.isObject() == false){
        showTip(tr("返回jso解析错误"), false);
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();

    showTip(tr("信息已发送到邮箱，注意查收"));
    // qDebug() << "id = " << id << " res = " << res << " err = " << err;
    // 调用对应的逻辑, 根据id回调
    // if(_handlers.empty() == false)
        _handlers[id](jsonDoc.object());

    return;
}

// 提交注册信息按钮的槽函数
// debug: 后期需要优化下面的验证的话，可以在优化的。比如输入的密码的长度限制，大小写字母限制可以使用正则表达式(gpt代写哈哈哈)
void RegisterDialog::on_confirm_btn_clicked(){
    // 先验证输入框是否有问题
    bool valid = checkUserValid();
    if(valid == false) return;
    valid = checkEmailValid();
    if(valid == false) return;
    valid = checkPassValid();
    if(valid == false) return;
    valid = checkConfirmValid();
    if(valid == false) return;
    valid = checkVarifyValid();
    if(valid == false) return;

    // 发送http请求注册用户
    QJsonObject json_obj;
    json_obj["user"] = ui->user_edit->text();
    json_obj["email"] = ui->email_edit->text();
    json_obj["passwd"] = xorString(ui->pass_edit->text());
    json_obj["confirm"] = xorString(ui->confirm_edit->text());
    json_obj["varifycode"] = ui->varify_edit->text();
    HttpMgr::GetInstance()->PostHttpReq(QUrl(gate_url_prefix + "/user_register"), json_obj, ReqId::ID_REG_USER, Modules::REGISTERMOD);
}

// 注册成功后的页面切换
void RegisterDialog::ChangeTipPage(){
    _countdown_timer->stop();
    ui->stackedWidget->setCurrentWidget(ui->page_2);

    // 启动定时器，设置间隔为1000ms（1s）
    _countdown_timer->start(1000);
}

// 提示函数(注意函数一旦发生改动的话，调用这个函数的地方也是要发生改动的，不发生改动的话，是可以加上默认参数的)
void RegisterDialog::showTip(QString errstr, bool b_ok){
    if(b_ok == true)
        ui->err_tip->setProperty("state", "normal");
    else
        ui->err_tip->setProperty("state", "err");

    ui->err_tip->setText(errstr);
    repolish(ui->err_tip);
}

// 输入框的验证
bool RegisterDialog::checkUserValid(){
    if("" == ui->user_edit->text()){
        AddTipErr(TipErr::TIP_USER_ERR, tr("用户名不能为空"));
        return false;
    }
    DelTipErr(TipErr::TIP_USER_ERR);
    return true;
}
bool RegisterDialog::checkEmailValid(){
    // 验证邮箱的地址正则表达式
    auto email = ui->email_edit->text();
    if(email == "") return false;
    // 邮箱地址的正则表达式
    QRegularExpression regExp(R"((\w+)(\.|_)?(\w*)@(\w+)(\.(\w+))+)");
    bool match = regExp.match(email).hasMatch();
    if(match == false){
        // 提示邮箱不正确
        AddTipErr(TipErr::TIP_EMAIL_ERR, tr("邮箱地址不正确"));
        return false;
    }

    DelTipErr(TipErr::TIP_EMAIL_ERR);
    return true;
}
bool RegisterDialog::checkPassValid(){
    auto pass = ui->pass_edit->text();
    if(pass.length() < 4 || pass.length() > 30){
        // 提示长度不对
        AddTipErr(TipErr::TIP_PWD_ERR, tr("密码长度应为4~30"));
        return false;
    }

    // 创建一个正则表达式对象，按照上述密码要求
    // 这个正则表达式的解释：^[a-zA-Z0-9!@#$%^&*]{4,30}$ 密码长度至少4，可以是字母、数字和特定的特殊字符
    QRegularExpression regExp("^[a-zA-Z0-9!@#$%^&*]{4,30}$"); // 问gpt
    bool match = regExp.match(pass).hasMatch();
    if(match == false){
        // 提示字符非法
        AddTipErr(TipErr::TIP_PWD_ERR, tr("不能包含非法字符"));
        return false;
    }

    DelTipErr(TipErr::TIP_PWD_ERR);

    auto confirm = ui->confirm_edit->text();
    if(pass != confirm){
        // 提示密码不匹配
        AddTipErr(TipErr::TIP_PWD_CONFIRM, tr("密码和确认密码不匹配"));
        return false;
    }else{
        DelTipErr(TipErr::TIP_PWD_CONFIRM);
    }

    return true;
}
bool RegisterDialog::checkConfirmValid(){
    auto confirm = ui->pass_edit->text();
    if(confirm.length() < 4 || confirm.length() > 30){
        // 提示长度不对
        AddTipErr(TipErr::TIP_CONFIRM_ERR, tr("密码长度应为4~30"));
        return false;
    }

    // 创建一个正则表达式对象，按照上述密码要求
    // 这个正则表达式的解释：^[a-zA-Z0-9!@#$%^&*]{4,30}$ 密码长度至少4，可以是字母、数字和特定的特殊字符
    QRegularExpression regExp("^[a-zA-Z0-9!@#$%^&*]{4,30}$"); // 问gpt
    bool match = regExp.match(confirm).hasMatch();
    if(match == false){
        // 提示字符非法
        AddTipErr(TipErr::TIP_CONFIRM_ERR, tr("不能包含非法字符"));
        return false;
    }

    DelTipErr(TipErr::TIP_PWD_ERR);

    auto pass = ui->pass_edit->text();
    if(pass != confirm){
        // 提示密码不匹配
        AddTipErr(TipErr::TIP_PWD_CONFIRM, tr("密码和确认密码不匹配"));
        return false;
    }else{
        DelTipErr(TipErr::TIP_PWD_CONFIRM);
    }

    return true;
}
bool RegisterDialog::checkVarifyValid(){
    if("" == ui->varify_edit->text()){
        AddTipErr(TipErr::TIP_VARIFY_ERR, tr("验证码不能为空"));
        return false;
    }

    DelTipErr(TipErr::TIP_VARIFY_ERR);
    return true;
}

// （err_tip 提示框的设置）添加和删除错误
void RegisterDialog::AddTipErr(TipErr err, QString tip){
    _tip_errs[err] = tip;
    showTip(tip, false);
}
void RegisterDialog::DelTipErr(TipErr err){
    // 移除前加上是否为空的判断，不然会引发奔溃；估计是先执行了DelTipErr
    if(_tip_errs.empty() == false)
        _tip_errs.remove(err);
    // 没有错误的话，ui->err_tip 错误提示框就不用显示内容了
    if(_tip_errs.empty() == true){
        ui->err_tip->clear();
        return;
    }
    showTip(_tip_errs.first(), false);
}

// 返回按钮的槽函数中停止定时器并发送切换登录的信号
void RegisterDialog::on_return_btn_clicked()
{
    _countdown_timer->stop();
    emit sigSwitchLogin();
}
// 取消注册也发送切换登录信号
void RegisterDialog::on_cancel_btn_clicked()
{
    _countdown_timer->stop();
    emit sigSwitchLogin();
}


